using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using Atomic.Libraries;
using Atomic.Libraries.Mathematics;
using Atomic.Libraries.Mathematics.Functions;
using Atomic.Libraries.Mathematics.Statistics;
using Atomic.Libraries.Plotting.Functions;

namespace Atomic.Thermodynamics.StateEquations
{
	[Serializable]
	[DebuggerDisplay("{DebuggerDisplay}")]
	public class BirchMurnaghan5 : IStateEquation
	{
		private double e0, v0, b0, bp0, bpp0;
		private Vector x;

		public BirchMurnaghan5(double e0, double v0, double b0, double bp0, double bpp0, Vector x)
		{
			this.e0 = e0;
			this.v0 = v0;
			this.b0 = b0;
			this.bp0 = bp0;
			this.bpp0 = bpp0;
			this.x = x;
		}

		public static void Fit(IEnumerable<IVolumeEnergyPoint> points, out double e0, out double v0, out double b0, out double bp0, out double bpp0, out Vector x)
		{
			if (points == null)
			{
				throw new ArgumentNullException();
			}

			x = BirchMurnaghan.Solve5(points.ToArray(), out e0, out v0, out b0, out bp0, out bpp0);
		}

		public static FittedBirchMurnaghan5 Fit(IEnumerable<IVolumeEnergyPoint> points)
		{
			double e0, v0, b0, bp0, bpp0;
			Vector x;
			Fit(points, out e0, out v0, out b0, out bp0, out bpp0, out x);

			return new FittedBirchMurnaghan5(e0, v0, b0, bp0, bpp0, x, points);
		}

		public static FittedBirchMurnaghan5 Fit(params IVolumeEnergyPoint[] points)
		{
			return Fit((IEnumerable<IVolumeEnergyPoint>)points);
		}

		/// <summary>
		/// Energy (eV) as a function of volume (Å^3).
		/// </summary>
		public double Energy(double volume)
		{
			double[,] a = new double[1, 5];
			for (int i = 0; i < 5; i++)
			{
				a[0, 0] = 1.0;
				for (int j = 1; j < 5; j++)
				{
					a[0, j] = Math.Pow(volume, -2.0 / 3.0 * j);
				}
			}

			// Currently using vector representation directly!
			return (new Matrix(a) * x)[0];
		}

		public double Pressure(double volume)
		{
			throw new NotImplementedException();
		}

		public double BulkModulus(double volume)
		{
			throw new NotImplementedException();
		}
				
		/// <summary>
		/// Equilibrium energy (eV).
		/// </summary>
		public double EquilibriumEnergy
		{
			get
			{
				return e0;
			}
		}
	
		/// <summary>
		/// Equilibrium volume (Å^3).
		/// </summary>
		public double EquilibriumVolume
		{
			get
			{
				return v0;
			}
		}

		/// <summary>
		/// Equilibrium bulk modulus (eV/Å^3).
		/// </summary>
		public double EquilibriumBulkModulus
		{
			get
			{
				return b0;
			}
		}

		public double EquilibriumBulkModulusPressureDerivative
		{
			get
			{
				return bp0;
			}
		}

		public double EquilibriumBulkModulusPressureSecondDerivative
		{
			get
			{
				return bpp0;
			}
		}

		private string DebuggerDisplay
		{
			get
			{
				return string.Format("E0 = {0}, V0 = {1}, B0 = {2}, B0' = {3}, B0'' = {4}", e0, v0, b0, bp0, bpp0);
			}
		}
	}
}
